package com.gitee.feizns.web.utils;

import lombok.Getter;
import lombok.SneakyThrows;

import javax.crypto.Cipher;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;

/**
 * RasKeyPair pair = generatorKeyPair(1024);
 * String secretText = encrypt("abc", pair.toPublicKey());
 * System.out.println(secretText);  //drkmfcUbDyv5Szb8qjYeSVZ2vWHcCfQ1ZI1rIQKeieYBXJ4VnrSTaCiGwcdIPD7HQZQW84REmADKqlWrvPet1FG26jlotTZApssD1EdLioWDIC+SF39zHpnQEHyS7zIp/dGnI45GfW1e82ouUZfKRsrktzS/J1Rw/2yeHAEGiAE=
 * String original = decrypt(secretText, pair.toPrivateKey());
 * System.out.println(original);    //abc
 *
 * @author feizns
 * @since 2019/6/25
 */
public class SecurityUtils {

    private String method;

    public SecurityUtils(String method) {
        this.method = method;
    }

    public String decrypt(String original, Key key) {
        try {
            byte[] bytes = Base64.getDecoder().decode(original.getBytes());
            Cipher cipher = null;
            cipher = Cipher.getInstance(method);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(bytes));
        } catch (Exception e) {
            return null;
        }
    }

    @SneakyThrows
    public String encrypt(String original, Key key) {
        Cipher cipher = Cipher.getInstance(method);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return Base64.getEncoder().encodeToString(cipher.doFinal(original.getBytes()));
    }

    /**
     * @return
     */
    @SneakyThrows
    public RasKeyPair generatorKeyPair(int size) {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(method);
        SecureRandom secureRandom = new SecureRandom(new Date().toString().getBytes());

        keyPairGenerator.initialize(size, secureRandom);

        KeyPair keyPair = keyPairGenerator.genKeyPair();

        return new RasKeyPair(keyPair.getPublic().getEncoded(), keyPair.getPrivate().getEncoded());
    }

    @Getter
    public class RasKeyPair {

        /**
         *
         */
        private byte[] publicKey;

        /**
         *
         */
        private byte[] privateKey;

        public RasKeyPair(byte[] publicKey, byte[] privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public RasKeyPair(String base64Pbk, String base64Pvk) {
            this.publicKey = Base64.getDecoder().decode(base64Pbk.getBytes());
            this.privateKey = Base64.getDecoder().decode(base64Pvk.getBytes());
        }

        public String getBase64PublicKey() {
            return Base64.getEncoder().encodeToString(publicKey);
        }

        public String getBase64PrivateKey() {
            return Base64.getEncoder().encodeToString(privateKey);
        }

        public Key toPublicKey() {
            return SecurityUtils.this.getPublicKey(publicKey);
        }

        public Key toPrivateKey() {
            return SecurityUtils.this.getPrivateKey(privateKey);
        }

    }

    public PrivateKey getPrivateKey(String base64Pk) {
        return getPrivateKey(Base64.getDecoder().decode(base64Pk.getBytes()));
    }

    @SneakyThrows
    private PrivateKey getPrivateKey(byte[] bytes) {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory kf = KeyFactory.getInstance(method);
        return kf.generatePrivate(spec);
    }

    @SneakyThrows
    private PublicKey getPublicKey(byte[] bytes) {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
        KeyFactory kf = KeyFactory.getInstance(method);
        return kf.generatePublic(spec);
    }

    public PublicKey getPublicKey(String base64Pk) {
        return getPublicKey(Base64.getDecoder().decode(base64Pk.getBytes()));
    }

}
